//============================================================================
// Name        : LinuxThreads
// Author      : DadaoII
// Version     : 1.0
// Copyright   : BSD
// Description : An MultiThread releated class wrapper for Linux/Windows.
//               Wrap Class LinuxEvent for Event type in Windows
//               Wrap ReleaseMutex() Function
// Date	       : Jan 2016, Apr 2016
//============================================================================

#ifndef CUSTOMIZED_THREADS_H_INCLUDED
#define CUSTOMIZED_THREADS_H_INCLUDED

#include "OSVersion.h"


#define WAIT_OBJECT_0   0x00000000
#define WAIT_TIMEOUT    0x00000102

#include <pthread.h>
#include <assert.h>


const int INFINITE = -1;

class LinuxEvent
{
public:
    LinuxEvent(bool bIsManualReset, bool bInitialSignaled);
    ~LinuxEvent();
    bool CreateEvent();
    bool Set();
    bool Reset();
    bool Wait(int t_ms);
private:
    bool IsInitialized();
    bool m_bIsManualReset;
    bool m_bEventStatus;
    bool m_bMutexInitialized;
    pthread_mutex_t m_mutex;
    bool m_bCondInitialized;
    pthread_cond_t m_cond;
};

LinuxEvent *CreateEvent(bool bManualReset, bool bInitialState);

unsigned int WaitForSingleObject(LinuxEvent *pEvent, int t_ms);

inline bool CloseHandle(LinuxEvent *pEvent)
{
    assert(pEvent);

    delete pEvent;

    return true;
}

inline bool SetEvent(LinuxEvent *pEvent)
{
    assert(pEvent);

    return pEvent->Set();
}

inline bool ResetEvent(LinuxEvent *pEvent)
{
    assert(pEvent);

    return pEvent->Reset();
}


inline int ReleaseMutex(pthread_mutex_t mutex)
{
    return pthread_mutex_unlock(&mutex);
}

unsigned int WaitForSingleObject(pthread_mutex_t mutex, int t_ms);


#include <chrono>
using namespace std::chrono;
class TimedEvent
{
public:
	TimedEvent(unsigned char bOn = 0, unsigned long timeInt = 2000){
		CreateTimedEvent(bOn, timeInt);
	}
	void CreateTimedEvent(unsigned char bOn = 0, unsigned long timeInt = 2000);
	friend bool SetEvent(TimedEvent& te);
	inline friend bool ResetEvent(TimedEvent& te){
		return ResetEvent(te.m_Event);
	}
	friend bool CloseTimedEvent(TimedEvent& te);
	inline friend unsigned long WaitForSingleObject(TimedEvent& te, unsigned long dwTimeInMS){
		return WaitForSingleObject(te.m_Event, dwTimeInMS);
	}
	inline void ClearPrevTick(){
		m_bPrevSet = 0;
	}
protected:
	LinuxEvent* m_Event;
	unsigned char m_bPrevSet;
	system_clock::time_point m_prevTick;
	unsigned long m_timeInt;
};

#define MAX_NUM_EVENTS_IN_A_LIST 100
class ATOM_Event_List
{
public:
	ATOM_Event_List();
	ATOM_Event_List(int nHandle, BYTE* pTimedHandle,
		unsigned long *pWaitTimeInMS = 0){
		Initialize(nHandle, pTimedHandle, pWaitTimeInMS);
	}
	~ATOM_Event_List(){
		CloseAll();
	}
	bool Initialize(int nHandle, BYTE* pTimedHandle,
		unsigned long *pWaitTimeInMS = 0);
	bool ReInstate();
	void CloseAll();
	bool Wait(int nEventNum, unsigned long dwWaitTimeInMS = 0);
	bool Set(int nEventNum);
protected:
	void** m_pHandleArray;
	BYTE* m_pbTimedHandle;
	int m_nHandleCount;
};


#endif // CUSTOMIZED_THREADS_H_INCLUDED
